#include "../../pch.h"
#include "REFNameTable.h"

namespace BFX
{

REFNameTable::~REFNameTable()
{
}

REFHashNameTable::REFHashNameTable()
{
	m_pBuckets = new REF<Entry>[HASH_MASK + 1];
}
REFHashNameTable::~REFHashNameTable()
{
	Clear();
	delete[] m_pBuckets;
}

UniString REFHashNameTable::Get(UCSTR pchName, int iOffset, int nLength)
{
	if (nLength == 0)
		return UniString();

	return Get(UniString(pchName + iOffset, nLength));
}
UniString REFHashNameTable::Get(const UniString& strName)
{
	if (strName.IsEmpty())
		return strName;

	int nHashCode = GetHashCode(strName);
	int nHashBucket = nHashCode & HASH_MASK;
	Entry* pEntry;

	// lookup entry to find matches
	for (pEntry = m_pBuckets[nHashBucket]; pEntry != NULL; pEntry = pEntry->m_pNext)
	{
		if (pEntry->m_nHashCode == nHashCode && pEntry->m_str == strName)
			return pEntry->m_str;
	}

	return UniString();
}
UniString REFHashNameTable::Add(UCSTR pchName, int iOffset, int nLength)
{
	if (nLength == 0)
		return UniString();

	return Add(UniString(pchName + iOffset, nLength));
}
UniString REFHashNameTable::Add(const UniString& strName)
{
	if (strName.IsEmpty())
		return strName;

	int nHashCode = GetHashCode(strName);
	int nHashBucket = nHashCode & HASH_MASK;
	Entry* pEntry;

	// lookup entry to find matches
	for (pEntry = m_pBuckets[nHashBucket]; pEntry != NULL; pEntry = pEntry->m_pNext)
	{
		if (pEntry->m_nHashCode == nHashCode && pEntry->m_str == strName)
			return pEntry->m_str;
	}

	// create a new entry
	pEntry = new Entry(strName, nHashCode, m_pBuckets[nHashBucket]);
	m_pBuckets[nHashBucket] = pEntry;
	m_nSize ++;

	return pEntry->m_str;
}

void REFHashNameTable::Clear()
{
	if (m_nSize == 0)
		return;
	for (int nHashBucket = 0; nHashBucket < (HASH_MASK + 1); nHashBucket++)
	{
		m_pBuckets[nHashBucket] = NULL;	// don't worry, that's fine.
	}
	m_nSize = 0;
}

int REFHashNameTable::GetHashCode(const UniString& strName)
{
	int nHashCode = strName.GetLength();
	// use key length to eliminate the rangecheck
	for (int i = 0; i < strName.GetLength(); i++)
		nHashCode += (nHashCode << 7 ) ^ strName[i];
	// mix it a bit more
	nHashCode -= nHashCode >> 17;
	nHashCode -= nHashCode >> 11;
	nHashCode -= nHashCode >> 5;

	return nHashCode;
}

}	//	namespace BFX
